package com.pan.alg.structure;

import java.util.concurrent.BlockingQueue;
import java.util.concurrent.DelayQueue;
import java.util.concurrent.Delayed;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * @author by panstark
 * @description
 * @notice
 * @date 2021/8/9
 */
public class DelayQueueDemo {

    public static void main(String[] args) {

        BlockingQueue<DelayTask> queue = new DelayQueue<DelayTask>();
        for (int i = 0; i < 10; i++) {
            try {
                queue.put(new DelayTask("work " + i));
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

        ThreadGroup group = new ThreadGroup("Consumers");
//        for (int i = 0; i < 5; i++) {
        new Thread(group, new DelayTaskComsumer(queue)).start();
//        }


        while (DelayTask.taskCount.get() > 0) {
            try {
                Thread.sleep(50);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

        group.interrupt();
        System.out.println("Main thread finished");
    }

}


class DelayTaskComsumer extends Thread {
    private final BlockingQueue<DelayTask> queue;

    public DelayTaskComsumer(BlockingQueue<DelayTask> queue) {
        this.queue = queue;
    }

    @Override
    public void run() {
        DelayTask task = null;
        try {
            while (true) {
                task = queue.take();
                task.execTask();
                DelayTask.taskCount.decrementAndGet();
            }
        } catch (InterruptedException e) {
            System.out.println(getName() + " finished");
        }
    }
}

class DelayTask implements Delayed{

    long startTime = System.currentTimeMillis();
    protected final String taskName;
    protected final long delayTime;

    protected static final AtomicInteger taskCount = new AtomicInteger(0);

    /**
     * 定时任务之间的启动时间间隔在1~2s之间，timeCost表示处理此任务需要的时间，本示例中为2s
      */
    public DelayTask(String taskName) {
        this.taskName = taskName;
        taskCount.incrementAndGet();
        delayTime = System.currentTimeMillis()+1000 + (long) (Math.random() * 1000);
    }

    @Override
    public int compareTo(Delayed o) {
        return (int) (this.delayTime - ((DelayTask) o).delayTime);
    }

    @Override
    public long getDelay(TimeUnit unit) {
        long expirationTime = delayTime - System.currentTimeMillis();
        return unit.convert(expirationTime, TimeUnit.MILLISECONDS);
    }

    public void execTask() {
        System.out.println("Task " + taskName + ": putTaskTime=" + startTime + ",excuteTaskTime="
                + delayTime + ",delay=" + (delayTime -startTime)+"ms,Thread:"+Thread.currentThread().getName());
    }

}